<!-- @format -->

<template>
	<view>
		<view
			class="e-sticky-wrap"
			:class="[elClass]"
			:style="{
				height: fixed ? height + 'px' : 'auto'
			}"
		>
			<view
				class="sticky"
				:style="{
					position: fixed ? 'fixed' : 'static',
					top: stickyTop + 'px',
					left: left + 'px',
					width: width === 'auto' ? 'auto' : width + 'px',
					zIndex: eZIndex
				}"
			>
				<slot></slot>
			</view>
		</view>
	</view>
</template>

<script>
export default {
	name: 'eSticky',

	props: {
		// 吸顶容器到顶部某个距离的时候，进行吸顶，在H5平台，NavigationBar为44px
		offsetTop: {
			type: Number,
			default: 0
		},
		// 列表中的索引值
		index: {
			type: [Number, String],
			default: ''
		},
		// 是否开启吸顶功能 产生报错（在onshow 更改此值为 true onhide 变为 false）
		enable: {
			type: Boolean,
			default: true
		},
		// h5顶部导航栏的高度
		h5NavHeight: {
			type: [Number, String],
			default: 44
		},
		// z-index值
		zIndex: {
			type: [Number, String],
			default: ''
		},
		// 是否自定义头部
		customNav: {
			type: Boolean,
			default: false
		}
	},
	data() {
		return {
			fixed: false,
			height: 'auto',
			stickyTop: 0,
			elClass: 'class0',
			left: 0,
			width: 'auto'
		};
	},
	watch: {
		offsetTop(val) {
			this.initObserver();
		},
		enable(val) {
			if (val === false) {
				this.fixed = false;
				this.disconnectObserver('contentObserver');
			} else {
				this.initObserver();
			}
		},
		fixed(val) {
			this.$emit('sticky', val);
		}
	},
	computed: {
		eZIndex() {
			return this.zIndex ? this.zIndex : 99;
		}
	},
	created() {
		this.elClass = 'class' + this.index;
	},
	mounted() {
		this.initObserver();
	},
	methods: {
		// 增加单位
		addUnit(value = 'auto', unit = 'rpx') {
			value = String(value);
			return this.number(value) ? `${value}${unit}` : value;
		},
		// 验证十进制数字
		number(value) {
			return /^(?:-?\d+|-?\d{1,3}(?:,\d{3})+)?(?:\.\d+)?$/.test(value);
		},
		// 获取节点
		getDomInfo(selector, all) {
			return new Promise((resolve) => {
				uni.createSelectorQuery()
					.in(this)
					[all ? 'selectAll' : 'select'](selector)
					.boundingClientRect((rect) => {
						if (all && Array.isArray(rect) && rect.length) {
							resolve(rect);
						}
						if (!all && rect) {
							resolve(rect);
						}
					})
					.exec();
			});
		},
		initObserver() {
			if (!this.enable) return;
			const { offsetTop, h5NavHeight, customNav } = this;
			// #ifdef H5
			if (customNav) {
				this.stickyTop = offsetTop !== 0 ? offsetTop : 0;
			} else {
				this.stickyTop = offsetTop !== 0 ? offsetTop + h5NavHeight : h5NavHeight;
			}
			// #endif
			// #ifndef H5
			this.stickyTop = offsetTop !== 0 ? offsetTop : 0;
			// #endif

			this.disconnectObserver('contentObserver');
			this.getDomInfo('.' + this.elClass).then((res) => {
				this.height = res.height;
				this.left = res.left;
				this.width = res.width;
				this.$nextTick(() => {
					this.observeContent();
				});
			});
		},
		observeContent() {
			this.disconnectObserver('contentObserver');
			const contentObserver = this.createIntersectionObserver({
				thresholds: [0, 0.5, 1]
			});
			contentObserver.relativeToViewport({
				top: -this.stickyTop
			});
			contentObserver.observe('.' + this.elClass, (res) => {
				if (!this.enable) return;
				this.setFixed(res.boundingClientRect.top);
			});
			this.contentObserver = contentObserver;
		},
		setFixed(top) {
			const fixed = top < this.stickyTop;
			if (fixed) this.$emit('fixed', this.index);
			else if (this.fixed) this.$emit('unfixed', this.index);
			this.fixed = fixed;
		},
		disconnectObserver(observerName) {
			const observer = this[observerName];
			observer && observer.disconnect();
		}
	},
	beforeDestroy() {
		this.disconnectObserver('contentObserver');
	}
};
</script>

<style scoped lang="scss">
/** @format */

.sticky {
	z-index: 99;
}
.e-sticky-wrap {
	transform: none !important;
}
</style>
